package instructions

import (
	"fmt"
	"jvm/nzpJvm/instructions/base"
	"jvm/nzpJvm/instructions/comparisons"
	"jvm/nzpJvm/instructions/constants"
	"jvm/nzpJvm/instructions/control"
	"jvm/nzpJvm/instructions/conversions"
	"jvm/nzpJvm/instructions/extended"
	"jvm/nzpJvm/instructions/loads"
	"jvm/nzpJvm/instructions/math"
	"jvm/nzpJvm/instructions/references"
	"jvm/nzpJvm/instructions/stack"
	"jvm/nzpJvm/instructions/stores"
	"jvm/nzpJvm/instructions/utils"
)

// 创建指令对象的工厂
// 抛出异常的指令是还没有实现的指令
// 没有实现所有的指令，但是基本上实现了常用的指令
func NewInstruction(opcode byte) base.Instruction {
	switch opcode {
	case utils.OP_nop:
		return &constants.NOP{}
	case utils.OP_aconst_null:
		return &constants.ACONST_NULL{}
	case utils.OP_iconst_m1:
		return &constants.ICONST_M1{}
	case utils.OP_iconst_0:
		return &constants.ICONST_0{}
	case utils.OP_iconst_1:
		return &constants.ICONST_1{}
	case utils.OP_iconst_2:
		return &constants.ICONST_2{}
	case utils.OP_iconst_3:
		return &constants.ICONST_3{}
	case utils.OP_iconst_4:
		return &constants.ICONST_4{}
	case utils.OP_iconst_5:
		return &constants.ICONST_5{}
	case utils.OP_lconst_0:
		return &constants.LCONST_0{}
	case utils.OP_lconst_1:
		return &constants.LCONST_1{}
	case utils.OP_fconst_0:
		return &constants.FCONST_0{}
	case utils.OP_fconst_1:
		return &constants.FCONST_1{}
	case utils.OP_fconst_2:
		return &constants.FCONST_2{}
	case utils.OP_dconst_0:
		return &constants.DCONST_0{}
	case utils.OP_dconst_1:
		return &constants.DCONST_1{}
	case utils.OP_bipush:
		return &constants.BIPUSH{}
	case utils.OP_sipush:
		return &constants.SIPUSH{}
	case utils.OP_ldc:
		return &constants.LDC{}
	case utils.OP_ldc_w:
		return &constants.LDC_W{}
	case utils.OP_ldc2_w:
		return &constants.LDC2_W{}
	case utils.OP_iload:
		return &loads.ILOAD{}
	case utils.OP_lload:
		return &loads.LLOAD{}
	case utils.OP_fload:
		return &loads.FLOAD{}
	case utils.OP_dload:
		return &loads.DLOAD{}
	case utils.OP_aload:
		return &loads.ALOAD{}
	case utils.OP_iload_0:
		return &loads.ILOAD_0{}
	case utils.OP_iload_1:
		return &loads.ILOAD_1{}
	case utils.OP_iload_2:
		return &loads.ILOAD_2{}
	case utils.OP_iload_3:
		return &loads.ILOAD_3{}
	case utils.OP_lload_0:
		return &loads.LLOAD_0{}
	case utils.OP_lload_1:
		return &loads.LLOAD_1{}
	case utils.OP_lload_2:
		return &loads.LLOAD_2{}
	case utils.OP_lload_3:
		return &loads.LLOAD_3{}
	case utils.OP_fload_0:
		return &loads.FLOAD_0{}
	case utils.OP_fload_1:
		return &loads.FLOAD_1{}
	case utils.OP_fload_2:
		return &loads.FLOAD_2{}
	case utils.OP_fload_3:
		return &loads.FLOAD_3{}
	case utils.OP_dload_0:
		return &loads.DLOAD_0{}
	case utils.OP_dload_1:
		return &loads.DLOAD_1{}
	case utils.OP_dload_2:
		return &loads.DLOAD_2{}
	case utils.OP_dload_3:
		return &loads.DLOAD_3{}
	case utils.OP_aload_0:
		return &loads.ALOAD_0{}
	case utils.OP_aload_1:
		return &loads.ALOAD_1{}
	case utils.OP_aload_2:
		return &loads.ALOAD_2{}
	case utils.OP_aload_3:
		return &loads.ALOAD_3{}
	case utils.OP_iaload:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_laload:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_faload:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_daload:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_aaload:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_baload:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_caload:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_saload:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_istore:
		return &stores.ISTORE{}
	case utils.OP_lstore:
		return &stores.LSTORE{}
	case utils.OP_fstore:
		return &stores.FSTORE{}
	case utils.OP_dstore:
		return &stores.DSTORE{}
	case utils.OP_astore:
		return &stores.ASTORE{}
	case utils.OP_istore_0:
		return &stores.ISTORE_0{}
	case utils.OP_istore_1:
		return &stores.ISTORE_1{}
	case utils.OP_istore_2:
		return &stores.ISTORE_2{}
	case utils.OP_istore_3:
		return &stores.ISTORE_3{}
	case utils.OP_lstore_0:
		return &stores.LSTORE_0{}
	case utils.OP_lstore_1:
		return &stores.LSTORE_1{}
	case utils.OP_lstore_2:
		return &stores.LSTORE_2{}
	case utils.OP_lstore_3:
		return &stores.LSTORE_3{}
	case utils.OP_fstore_0:
		return &stores.FSTORE_0{}
	case utils.OP_fstore_1:
		return &stores.FSTORE_1{}
	case utils.OP_fstore_2:
		return &stores.FSTORE_2{}
	case utils.OP_fstore_3:
		return &stores.FSTORE_3{}
	case utils.OP_dstore_0:
		return &stores.DSTORE_0{}
	case utils.OP_dstore_1:
		return &stores.DSTORE_1{}
	case utils.OP_dstore_2:
		return &stores.DSTORE_2{}
	case utils.OP_dstore_3:
		return &stores.DSTORE_3{}
	case utils.OP_astore_0:
		return &stores.ASTORE_0{}
	case utils.OP_astore_1:
		return &stores.ASTORE_1{}
	case utils.OP_astore_2:
		return &stores.ASTORE_2{}
	case utils.OP_astore_3:
		return &stores.ASTORE_3{}
	case utils.OP_iastore:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_lastore:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_fastore:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_dastore:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_aastore:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_bastore:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_castore:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_sastore:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_pop:
		return &stack.POP{}
	case utils.OP_pop2:
		return &stack.POP2{}
	case utils.OP_dup:
		return &stack.DUP{}
	case utils.OP_dup_x1:
		return &stack.DUP_X1{}
	case utils.OP_dup_x2:
		return &stack.DUP_X2{}
	case utils.OP_dup2:
		return &stack.DUP2{}
	case utils.OP_dup2_x1:
		return &stack.DUP2_X1{}
	case utils.OP_dup2_x2:
		return &stack.DUP2_X2{}
	case utils.OP_swap:
		return &stack.SWAP{}
	case utils.OP_iadd:
		return &math.IADD{}
	case utils.OP_ladd:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_fadd:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_dadd:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_isub:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_lsub:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_fsub:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_dsub:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_imul:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_lmul:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_fmul:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_dmul:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_idiv:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_ldiv:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_fdiv:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_ddiv:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_irem:
		return &math.IREM{}
	case utils.OP_lrem:
		return &math.LREM{}
	case utils.OP_frem:
		return &math.FREM{}
	case utils.OP_drem:
		return &math.DREM{}
	case utils.OP_ineg:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_lneg:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_fneg:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_dneg:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_ishl:
		return &math.ISHL{}
	case utils.OP_lshl:
		return &math.LSHL{}
	case utils.OP_ishr:
		return &math.ISHR{}
	case utils.OP_lshr:
		return &math.LSHR{}
	case utils.OP_iushr:
		return &math.IUSHR{}
	case utils.OP_lushr:
		return &math.LUSHR{}
	case utils.OP_iand:
		return &math.IAND{}
	case utils.OP_land:
		return &math.LAND{}
	case utils.OP_ior:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_lor:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_ixor:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_lxor:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_iinc:
		return &math.IINC{}
	case utils.OP_i2l:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_i2f:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_i2d:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_l2i:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_l2f:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_l2d:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_f2i:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_f2l:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_f2d:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_d2i:
		return &conversions.D2I{}
	case utils.OP_d2l:
		return &conversions.D2L{}
	case utils.OP_d2f:
		return &conversions.D2F{}
	case utils.OP_i2b:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_i2c:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_i2s:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_lcmp:
		return &comparisons.LCMP{}
	case utils.OP_fcmpl:
		return &comparisons.FCMPL{}
	case utils.OP_fcmpg:
		return &comparisons.FCMPG{}
	case utils.OP_dcmpl:
		return &comparisons.DCMPL{}
	case utils.OP_dcmpg:
		return &comparisons.DCMPG{}
	case utils.OP_ifeq:
		return &comparisons.IFEQ{}
	case utils.OP_ifne:
		return &comparisons.IFNE{}
	case utils.OP_iflt:
		return &comparisons.IFLT{}
	case utils.OP_ifge:
		return &comparisons.IFGE{}
	case utils.OP_ifgt:
		return &comparisons.IFGT{}
	case utils.OP_ifle:
		return &comparisons.IFLE{}
	case utils.OP_if_icmpeq:
		return &comparisons.IF_ICMPEQ{}
	case utils.OP_if_icmpne:
		return &comparisons.IF_ICMPNE{}
	case utils.OP_if_icmplt:
		return &comparisons.IF_ICMPLT{}
	case utils.OP_if_icmpge:
		return &comparisons.IF_ICMPGE{}
	case utils.OP_if_icmpgt:
		return &comparisons.IF_ICMPGT{}
	case utils.OP_if_icmple:
		return &comparisons.IF_ICMPLE{}
	case utils.OP_if_acmpeq:
		return &comparisons.IF_ACMPEQ{}
	case utils.OP_if_acmpne:
		return &comparisons.IF_ACMPNE{}
	case utils.OP_goto:
		return &control.GOTO{}
	case utils.OP_jsr:
		return &extended.GOTO_W{}
	case utils.OP_ret:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_tableswitch:
		return &control.TABLE_SWITCH{}
	case utils.OP_lookupswitch:
		return &control.LOOKUP_SWITCH{}
	case utils.OP_ireturn:
		return &control.IRETURN{}
	case utils.OP_lreturn:
		return &control.LRETURN{}
	case utils.OP_freturn:
		return &control.FRETURN{}
	case utils.OP_dreturn:
		return &control.DRETURN{}
	case utils.OP_areturn:
		return &control.ARETURN{}
	case utils.OP_return:
		return &control.RETURN{}
	case utils.OP_getstatic:
		return &references.GET_STATIC{}
	case utils.OP_putstatic:
		return &references.PUT_STATIC{}
	case utils.OP_getfield:
		return &references.GET_FIELD{}
	case utils.OP_putfield:
		return &references.PUT_FIELD{}
	case utils.OP_invokevirtual:
		return &references.INVOKE_VIRTUAL{}
	case utils.OP_invokespecial:
		return &references.INVOKE_SPECIAL{}
	case utils.OP_invokestatic:
		return &references.INVOKE_STATIC{}
	case utils.OP_invokeinterface:
		return &references.INVOKE_INTERFACE{}
	case utils.OP_invokedynamic:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_new:
		return &references.NEW{}
	case utils.OP_newarray:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_anewarray:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_arraylength:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_athrow:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_checkcast:
		return &references.CHECK_CAST{}
	case utils.OP_instanceof:
		return &references.INSTANCE_OF{}
	case utils.OP_monitorenter:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_monitorexit:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_wide:
		return &extended.WIDE{}
	case utils.OP_multianewarray:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	case utils.OP_ifnull:
		return &extended.IFNULL{}
	case utils.OP_ifnonnull:
		return &extended.IFNONNULL{}
	case utils.OP_goto_w:
		return &extended.GOTO_W{}
	case utils.OP_jsr_w:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	default:
		panic(fmt.Errorf("unsupported opcode[ox%x]", opcode))
	}
}
